# 也就是说，先创建一个实例对象，之后不管创建多少个，返回的永远都是第一个实例对象的内存地址。可以这样实现：
import threading


# 重写new方法很固定，返回值必须是这个
# 这样就避免了创建多份。
# 创建第一个实例的时候，_instance是None，那么会分配空间创建实例。
# 此时的类属性已经被修改，_instance不再为None
# 那么当之后实例属性被创建的时候，由于_instance不为None。
# 则返回第一个实例对象的引用，即内存地址。
# 这样就应用了单例模式。
class A():
    _instance = None
    def __new__(cls,*args,**kwargs):
        if A._instance == None:
            A._instance = super().__new__(cls)
        return A._instance


a1 = A()
print(id(a1))
a2 = A()
print(id(a2))

print('并发场景'.center(50,'*'))

# 题外话：在并发多线程的场景下，创建单例对象可能会有问题，因为多个线程可能会同时进入if判断，然后创建多个实例对象。
# 解决这个问题，可以使用锁。
class AA():
    _instance = None
    _lock = threading.Lock()
    def __new__(cls,*args,**kwargs):
        if AA._instance is None:
            with AA._lock:
                # 在with块结束时，锁会自动释放
                if AA._instance is None:
                    AA._instance = super().__new__(cls)
        return AA._instance
aa = AA()
print(id(aa))
aa2 = AA()
print(id(aa2))